﻿// -------------------------------------------------------------------------
//    @FileName         :    NFBagPage.h
//    @Author           :    gaoyi
//    @Date             :    24-11-19
//    @Email            :    445267987@qq.com
//    @Module           :    NFBagPage
//
// -------------------------------------------------------------------------

// --- 文件总结 ---------------------------------------------------------------
// `NFBagPage` 定义背包页签的抽象接口与基类，`NFBagPageImpl<MAX_ITEM_NUM>`
// 提供共享内存向量存储实现：
// - 支持容量设置/增减格子、清空与排序
// - 基于 `NFGridItem` 的增删改查与校验（含 UUID/数量匹配）
// - 生成/解析客户端同步结构（BagPage、ItemGridCSData）
// - 维持已用格子计数与页签类型
//
// 说明：实现类保证在共享内存场景下使用，遵循项目 `NFShmVector` 语义。
// ---------------------------------------------------------------------------

#pragma once


#include <NFLogicCommon/NFItemOperator.h>
#include <NFLogicCommon/NFItemDefine.h>

#include "proto_common_item.nanopb.h"
#include "proto_common_bag.nanopb.h"
#include "proto_cs_cmd.nanopb.h"

class NFBagPage
{
public:
    NFBagPage()
    {
        if (EN_OBJ_MODE_INIT == NFShmMgr::Instance()->GetCreateMode())
        {
            CreateInit();
        }
        else
        {
            ResumeInit();
        }
    }

    int CreateInit()
    {
        Init();
        return 0;
    }

    int ResumeInit()
    {
        return 0;
    }

    virtual ~NFBagPage() = default;

    /**
     * @brief 初始化页签
     */
    virtual void Init();

public:
    /**
     * @brief 初始化页签（从客户端数据）
     * @param roleID 角色ID
     * @param iPageType 页签类型
     * @param stBagPage 背包页签数据
     * @return 0成功，非0失败
     */
    virtual int Init(uint64_t roleID, int iPageType, const proto_ff::BagPage& stBagPage) = 0;

    /**
     * @brief 生成客户端同步数据
     * @param pBagPage 输出背包页签数据
     * @return 0成功，非0失败
     */
    virtual int MakeCSData(proto_ff::BagPage* pBagPage) const = 0;

    /**
     * @brief 生成格子客户端同步数据
     * @param pRepeatedItemList 输出物品列表
     * @return 0成功，非0失败
     */
    virtual int MakeGridCSData(FF_IG_LIST* pRepeatedItemList) const = 0;

    /**
     * @brief 设置格子数据
     * @param stItemGridCSData 物品格子客户端数据
     * @return 0成功，非0失败
     */
    virtual int SetGrid(const proto_ff::ItemGridCSData& stItemGridCSData) = 0;

    /**
     * @brief 获取页签容量
     * @return 页签容量
     */
    virtual int GetCapacity() const = 0;

    /**
     * @brief 获取最大容量
     * @return 最大容量
     */
    virtual int GetMaxSize() const = 0;

    /**
     * @brief 清空所有物品
     * @return 0成功，非0失败
     */
    virtual int ClearAll() = 0;

    /**
     * @brief 增加容量
     * @param iNum 要增加的数量
     * @param pOrgCapacity 输出原容量（可选）
     * @param pNewCapacity 输出新容量（可选）
     * @return 0成功，非0失败
     */
    virtual int AddCapacity(int iNum, int* pOrgCapacity = nullptr, int* pNewCapacity = nullptr) = 0;

    /**
     * @brief 减少容量
     * @param iNum 要减少的数量
     * @param pOrgCapacity 输出原容量（可选）
     * @param pNewCapacity 输出新容量（可选）
     * @return 0成功，非0失败
     */
    virtual int DecCapacity(int iNum, int* pOrgCapacity = nullptr, int* pNewCapacity = nullptr) = 0;

    /**
     * @brief 设置容量
     * @param iNewCapacity 新容量
     * @return 0成功，非0失败
     */
    virtual int SetCapacity(int iNewCapacity) = 0;

    /**
     * @brief 根据索引获取物品
     * @param iIndex 格子索引
     * @return 物品指针（需要判空）
     */
    virtual NFGridItem* GetItemByIndex(int iIndex) = 0;

    /**
     * @brief 根据索引获取物品（const版本）
     * @param iIndex 格子索引
     * @return 物品指针（需要判空）
     */
    virtual const NFGridItem* GetItemByIndex(int iIndex) const = 0;

    /**
     * @brief 根据索引获取物品（输出版本）
     * @param pOutItem 输出物品
     * @param iIndex 格子索引
     * @return 0成功，非0失败
     */
    virtual int GetItemByIndex(NFGridItem* pOutItem, int iIndex) const = 0;

    /**
     * @brief 获取指定ID物品的总数量
     * @param iID 物品ID
     * @return 物品总数量
     */
    virtual uint64_t GetItemNum(int iID) const = 0;

    /**
     * @brief 获取所有物品
     * @param vecGridItem 输出物品列表
     * @return 0成功，非0失败
     */
    virtual int GetAllItemOut(std::vector<NFGridItem>& vecGridItem) const = 0;

    /**
     * @brief 根据UUID获取物品
     * @param uuid 物品UUID
     * @return 物品指针（需要判空）
     */
    virtual NFGridItem* GetItemByUUID(uint64_t uuid) = 0;

    /**
     * @brief 根据UUID获取物品（const版本）
     * @param uuid 物品UUID
     * @return 物品指针（需要判空）
     */
    virtual const NFGridItem* GetItemByUUID(uint64_t uuid) const = 0;

    /**
     * @brief 根据UUID获取物品（输出版本）
     * @param pOutItem 输出物品
     * @param uuid 物品UUID
     * @return 0成功，非0失败
     */
    virtual int GetItemByUUID(NFGridItem* pOutItem, uint64_t uuid) const = 0;

    /**
     * @brief 获取空格子
     * @param iIndex 输出格子索引
     * @return 物品指针（需要判空）
     */
    virtual NFGridItem* GetEmptyGrid(int& iIndex) = 0;

    /**
     * @brief 执行一次操作
     * @param iTargetGridIndex 目标格子索引
     * @param pItemOperator 物品操作器
     * @param pItemOrgOut 输出原始物品
     * @param pItemNewOut 输出新物品
     * @return 0成功，非0失败
     */
    virtual int DoOneOperation(int iTargetGridIndex, NFItemOperator* pItemOperator, NFGridItem* pItemOrgOut, NFGridItem* pItemNewOut) = 0;

    /**
     * @brief 添加物品
     * @param pItem 要添加的物品
     * @param pGridIndexOut 输出格子索引（可选）
     * @return 0成功，非0失败
     */
    virtual int AddItem(const NFGridItem* pItem, int* pGridIndexOut) = 0;

    /**
     * @brief 添加物品到指定格子
     * @param pItem 要添加的物品
     * @param iTargetGridIndex 目标格子索引
     * @return 0成功，非0失败
     */
    virtual int AddItemWithGrid(const NFGridItem* pItem, int iTargetGridIndex) = 0;

    /**
     * @brief 删除指定格子的物品
     * @param iTargetGridIndex 目标格子索引
     * @param pDelItemOut 输出删除的物品（可选）
     * @return 0成功，非0失败
     */
    virtual int DecItem(int iTargetGridIndex, NFGridItem* pDelItemOut) = 0;

    /**
     * @brief 增加指定格子物品数量
     * @param iTargetGridIndex 目标格子索引
     * @param iTargetIncreaseNum 要增加的数量
     * @param pItemOrgOut 输出原始物品（可选）
     * @param pItemNewOut 输出新物品（可选）
     * @return 0成功，非0失败
     */
    virtual int AddItemNum(int iTargetGridIndex, int iTargetIncreaseNum, NFGridItem* pItemOrgOut = NULL, NFGridItem* pItemNewOut = NULL) = 0;
    
    /**
     * @brief 减少指定格子物品数量
     * @param iTargetGridIndex 目标格子索引
     * @param iTargetDecreaseNum 要减少的数量
     * @param pItemOrgOut 输出原始物品（可选）
     * @param pItemNewOut 输出新物品（可选）
     * @return 0成功，非0失败
     */
    virtual int DecItemNum(int iTargetGridIndex, int iTargetDecreaseNum, NFGridItem* pItemOrgOut = NULL, NFGridItem* pItemNewOut = NULL) = 0;

    /**
     * @brief 检查格子是否为空
     * @param iTargetGridIndex 目标格子索引
     * @param pbIsEmpty 输出是否为空
     * @return 0成功，非0失败
     */
    virtual int CheckIsGridEmpty(int iTargetGridIndex, bool* pbIsEmpty) const = 0;

    /**
     * @brief 获取物品
     * @param pItemOut 输出物品
     * @param iTargetGridIndex 目标格子索引
     * @return 0成功，非0失败
     */
    virtual int GetItem(NFGridItem* pItemOut, int iTargetGridIndex) const = 0;

    /**
     * @brief 设置物品
     * @param iGridIndex 格子索引
     * @param pItem 要设置的物品
     * @param bPreCheckFlag 是否为预检查模式
     * @return 0成功，非0失败
     */
    virtual int SetItem(int iGridIndex, const NFGridItem* pItem, bool bPreCheckFlag = false) = 0;

    /**
     * @brief 检查数据是否匹配
     * @param iTargetGridIndex 目标格子索引
     * @param iItemID 物品ID
     * @param ullUID 物品UUID
     * @param iNum 物品数量（=0 不检查数量）
     * @return 0成功，非0失败
     */
    virtual int CheckDataMatched(int iTargetGridIndex, int iItemID, uint64_t ullUID, int iNum = 0) const = 0;

    /**
     * @brief 排序物品
     * @return 0成功，非0失败
     */
    virtual int Sort() = 0;

    /**
     * @brief 重置页签
     */
    virtual void Reset() = 0;

    /**
     * @brief 获取调试信息
     * @return 调试信息字符串
     */
    virtual const std::string GetDebugInfo() const = 0;

public:
    /**
     * @brief 获取页签类型
     * @return 页签类型
     */
    virtual int GetPageType() const { return m_iPageType; }

    /**
     * @brief 获取空格子数量
     * @return 空格子数量
     */
    virtual int GetEmptyGridNum() const { return (int)GetCapacity() - m_iUsedNum; }

    /**
     * @brief 获取已用格子数量
     * @return 已用格子数量
     */
    virtual int GetUsedGridNum() const { return m_iUsedNum; }

    /**
     * @brief 获取开启格子次数
     * @return 开启格子次数
     */
    virtual int GetOpenGridTimes() const { return m_iOpenGridTimes; }

protected:
    /** @brief 已用格子数量 */
    int m_iUsedNum;
    /** @brief 开启格子次数 */
    int m_iOpenGridTimes;
    /** @brief 容量（必须 <= MAX_WARE_NUM） */
    int m_iCapacity;
    /** @brief 页签类型 */
    int m_iPageType;
};

inline void NFBagPage::Init()
{
    m_iUsedNum = 0;
    m_iOpenGridTimes = 0;
    m_iPageType = 0;
    m_iCapacity = 0;
}

/**
 * @brief 背包页签实现类模板
 * @tparam MAX_ITEM_NUM 最大物品数量
 * 提供共享内存向量存储实现，支持容量管理、物品CRUD、客户端同步等功能
 */
template <size_t MAX_ITEM_NUM>
class NFBagPageImpl : public NFBagPage
{
public:
    /**
     * @brief 构造函数
     * 根据共享内存创建模式选择初始化方式
     */
    NFBagPageImpl()
    {
        if (EN_OBJ_MODE_INIT == NFShmMgr::Instance()->GetCreateMode())
        {
            CreateInit();
        }
        else
        {
            ResumeInit();
        }
    }

    /**
     * @brief 创建初始化
     * @return 0成功，非0失败
     */
    int CreateInit()
    {
        Init();
        return 0;
    }

    /**
     * @brief 恢复初始化（从共享内存恢复）
     * @return 0成功，非0失败
     */
    int ResumeInit()
    {
        return 0;
    }

    /**
     * @brief 析构函数
     */
    virtual ~NFBagPageImpl() = default;

    /**
     * @brief 初始化页签
     */
    void Init() override;

public:
    /**
     * @brief 初始化页签（从客户端数据）
     * @param roleID 角色ID
     * @param iPageType 页签类型
     * @param stBagPage 背包页签数据
     * @return 0成功，非0失败
     */
    int Init(uint64_t roleID, int iPageType, const proto_ff::BagPage& stBagPage) override;

    /**
     * @brief 生成客户端同步数据
     * @param pBagPage 输出背包页签数据
     * @return 0成功，非0失败
     */
    int MakeCSData(proto_ff::BagPage* pBagPage) const override;

    /**
     * @brief 生成格子客户端同步数据
     * @param pRepeatedItemList 输出物品列表
     * @return 0成功，非0失败
     */
    int MakeGridCSData(FF_IG_LIST* pRepeatedItemList) const override;

    /**
     * @brief 设置格子数据
     * @param stItem 物品格子客户端数据
     * @return 0成功，非0失败
     */
    int SetGrid(const proto_ff::ItemGridCSData& stItem) override;

    /**
     * @brief 增加容量
     * @param iNum 要增加的数量
     * @param pOrgCapacity 输出原容量（可选）
     * @param pNewCapacity 输出新容量（可选）
     * @return 0成功，非0失败
     */
    int AddCapacity(int iNum, int* pOrgCapacity = nullptr, int* pNewCapacity = nullptr) override;

    /**
     * @brief 减少容量
     * @param iNum 要减少的数量
     * @param pOrgCapacity 输出原容量（可选）
     * @param pNewCapacity 输出新容量（可选）
     * @return 0成功，非0失败
     */
    int DecCapacity(int iNum, int* pOrgCapacity = nullptr, int* pNewCapacity = nullptr) override;

    /**
     * @brief 设置容量
     * @param iNewCapacity 新容量
     * @return 0成功，非0失败
     */
    int SetCapacity(int iNewCapacity) override;

    /**
     * @brief 获取页签容量
     * @return 页签容量
     */
    int GetCapacity() const override;

    /**
     * @brief 获取最大容量
     * @return 最大容量
     */
    int GetMaxSize() const override;

    /**
     * @brief 清空所有物品
     * @return 0成功，非0失败
     */
    int ClearAll() override;

    /**
     * @brief 根据索引获取物品
     * @param iIndex 格子索引
     * @return 物品指针（需要判空）
     */
    NFGridItem* GetItemByIndex(int iIndex) override;

    /**
     * @brief 根据索引获取物品（const版本）
     * @param iIndex 格子索引
     * @return 物品指针（需要判空）
     */
    const NFGridItem* GetItemByIndex(int iIndex) const override;

    /**
     * @brief 根据索引获取物品（输出版本）
     * @param pOutItem 输出物品
     * @param iIndex 格子索引
     * @return 0成功，非0失败
     */
    int GetItemByIndex(NFGridItem* pOutItem, int iIndex) const override;

    /**
     * @brief 获取指定ID物品的总数量
     * @param iID 物品ID
     * @return 物品总数量
     */
    uint64_t GetItemNum(int iID) const override;

    /**
     * @brief 获取所有物品
     * @param vecGridItem 输出物品列表
     * @return 0成功，非0失败
     */
    int GetAllItemOut(std::vector<NFGridItem>& vecGridItem) const override;

    /**
     * @brief 根据UUID获取物品
     * @param uuid 物品UUID
     * @return 物品指针（需要判空）
     */
    NFGridItem* GetItemByUUID(uint64_t uuid) override;

    /**
     * @brief 根据UUID获取物品（const版本）
     * @param uuid 物品UUID
     * @return 物品指针（需要判空）
     */
    const NFGridItem* GetItemByUUID(uint64_t uuid) const override;

    /**
     * @brief 根据UUID获取物品（输出版本）
     * @param pOutItem 输出物品
     * @param uuid 物品UUID
     * @return 0成功，非0失败
     */
    int GetItemByUUID(NFGridItem* pOutItem, uint64_t uuid) const override;

    /**
     * @brief 获取空格子
     * @param iIndex 输出格子索引
     * @return 物品指针（需要判空）
     */
    NFGridItem* GetEmptyGrid(int& iIndex) override;

    /**
     * @brief 执行一次操作
     * @param iTargetGridIndex 目标格子索引
     * @param pItemOperator 物品操作器
     * @param pItemOrgOut 输出原始物品
     * @param pItemNewOut 输出新物品
     * @return 0成功，非0失败
     */
    int DoOneOperation(int iTargetGridIndex, NFItemOperator* pItemOperator, NFGridItem* pItemOrgOut, NFGridItem* pItemNewOut) override;

    /**
     * @brief 添加物品
     * @param pItem 要添加的物品
     * @param pGridIndexOut 输出格子索引（可选）
     * @return 0成功，非0失败
     */
    int AddItem(const NFGridItem* pItem, int* pGridIndexOut) override;

    /**
     * @brief 添加物品到指定格子
     * @param pItem 要添加的物品
     * @param iTargetGridIndex 目标格子索引
     * @return 0成功，非0失败
     */
    int AddItemWithGrid(const NFGridItem* pItem, int iTargetGridIndex) override;

    /**
     * @brief 删除指定格子的物品
     * @param iTargetGridIndex 目标格子索引
     * @param pDelItemOut 输出删除的物品（可选）
     * @return 0成功，非0失败
     */
    int DecItem(int iTargetGridIndex, NFGridItem* pDelItemOut) override;

    /**
     * @brief 增加指定格子物品数量
     * @param iTargetGridIndex 目标格子索引
     * @param iTargetIncreaseNum 要增加的数量
     * @param pItemOrgOut 输出原始物品（可选）
     * @param pItemNewOut 输出新物品（可选）
     * @return 0成功，非0失败
     */
    int AddItemNum(int iTargetGridIndex, int iTargetIncreaseNum, NFGridItem* pItemOrgOut = NULL, NFGridItem* pItemNewOut = NULL) override;
    
    /**
     * @brief 减少指定格子物品数量
     * @param iTargetGridIndex 目标格子索引
     * @param iTargetDecreaseNum 要减少的数量
     * @param pItemOrgOut 输出原始物品（可选）
     * @param pItemNewOut 输出新物品（可选）
     * @return 0成功，非0失败
     */
    int DecItemNum(int iTargetGridIndex, int iTargetDecreaseNum, NFGridItem* pItemOrgOut = NULL, NFGridItem* pItemNewOut = NULL) override;

    /**
     * @brief 检查格子是否为空
     * @param iTargetGridIndex 目标格子索引
     * @param pbIsEmpty 输出是否为空
     * @return 0成功，非0失败
     */
    int CheckIsGridEmpty(int iTargetGridIndex, bool* pbIsEmpty) const override;

    /**
     * @brief 获取物品
     * @param pItemOut 输出物品
     * @param iTargetGridIndex 目标格子索引
     * @return 0成功，非0失败
     */
    int GetItem(NFGridItem* pItemOut, int iTargetGridIndex) const override;

    /**
     * @brief 设置物品
     * @param iGridIndex 格子索引
     * @param pItem 要设置的物品
     * @param bPreCheckFlag 是否为预检查模式
     * @return 0成功，非0失败
     */
    int SetItem(int iGridIndex, const NFGridItem* pItem, bool bPreCheckFlag = false) override;

    /**
     * @brief 检查数据是否匹配
     * @param iTargetGridIndex 目标格子索引
     * @param iItemID 物品ID
     * @param ullUID 物品UUID
     * @param iNum 物品数量（=0 不检查数量）
     * @return 0成功，非0失败
     */
    int CheckDataMatched(int iTargetGridIndex, int iItemID, uint64_t ullUID, int iNum = 0) const override;

    /**
     * @brief 排序物品
     * @return 0成功，非0失败
     */
    int Sort() override;

    /**
     * @brief 重置页签
     */
    void Reset() override;

    /**
     * @brief 获取调试信息
     * @return 调试信息字符串
     */
    const std::string GetDebugInfo() const override;

private:
    /**
     * @brief 检查格子索引是否有效
     * @param dwGridIndex 格子索引
     * @return 0有效，非0无效
     */
    int CheckValidGridIndex(uint32_t dwGridIndex) const;
    
    /**
     * @brief 检查页签是否已满
     * @return true已满，false未满
     */
    bool IsFull() const;
    
    /**
     * @brief 查找空格子索引
     * @return 空格子索引（INVALID_ID表示未找到）
     */
    int FindEmptyGridIndex() const;

protected:
    /** @brief 物品列表（共享内存向量） */
    NFShmVector<NFGridItem, MAX_ITEM_NUM> m_astItemList;
    /** @brief 角色ID */
    uint64_t m_roleID;
};

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::GetCapacity() const
{
    NF_ASSERT(m_iCapacity == m_astItemList.size());
    return m_iCapacity;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::GetMaxSize() const
{
    NF_ASSERT(MAX_ITEM_NUM == m_astItemList.max_size());
    return MAX_ITEM_NUM;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::ClearAll()
{
    LOG_DEBUG(m_roleID, "clear this bag page");
    Init();
    return 0;
}

template <size_t MAX_ITEM_NUM>
void NFBagPageImpl<MAX_ITEM_NUM>::Init()
{
    NFBagPage::Init();
    m_roleID = 0;
    m_astItemList.resize(0);
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::Init(uint64_t roleID, int iPageType, const proto_ff::BagPage& stBagPage)
{
    m_roleID = roleID;
    m_iPageType = iPageType;
    m_iOpenGridTimes = stBagPage.buy_grids_times();
    m_iCapacity = stBagPage.max_grids();
    if (m_iCapacity > m_astItemList.max_size())
    {
        LOGSVR_ERROR("Grid size Error: " << m_iCapacity << " Max: " << m_astItemList.max_size());
        m_iCapacity = m_astItemList.max_size();
    }
    m_iUsedNum = 0;
    m_astItemList.resize(m_iCapacity);
    NF_ASSERT(m_iCapacity == m_astItemList.size());

    for (int i = 0; i < stBagPage.grids_size(); i++)
    {
        const proto_ff::ItemGridCSData& stItem = stBagPage.grids(i);
        int iIndex = stItem.index();
        if (iIndex < 0 || iIndex >= m_astItemList.size())
        {
            LOGSVR_FATAL(" Item Be Delete: " << stItem.DebugString());
            continue;
        }
        int iRetCode = SetGrid(stItem);
        CHECK_RET(iRetCode, "Set Grid Failed:{} \n", stBagPage.grids(i).DebugString());
        m_iUsedNum++;
    }

    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::MakeCSData(proto_ff::BagPage* pBagPage) const
{
    CHECK_NULL(0, pBagPage);
    pBagPage->set_max_grids(m_iCapacity);
    pBagPage->set_buy_grids_times(m_iOpenGridTimes);
    return MakeGridCSData(pBagPage->mutable_grids());
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::MakeGridCSData(FF_IG_LIST* pRepeatedItemList) const
{
    CHECK_NULL(0, pRepeatedItemList);
    for (int i = 0; i < static_cast<int>(m_astItemList.size()); i++)
    {
        auto& item = m_astItemList[i];
        if (!NFItemUtil::IsEmptyGrid(item))
        {
            NFItemUtil::ItemToCSData(item, *pRepeatedItemList->Add(), i);
        }
    }
    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::SetGrid(const proto_ff::ItemGridCSData& stItem)
{
    int iIndex = stItem.index();
    CHECK_EXPR(iIndex >= 0 && iIndex < (int) m_astItemList.size(), -1, "Index Error: {}", iIndex);
    CHECK_EXPR(m_astItemList[iIndex].m_stBase.id == 0, -1, "set item error: grid has item: {} {}", iIndex, m_astItemList[iIndex].m_stBase.id);

    int iRet = NFItemUtil::ItemFromCSData(m_astItemList[iIndex], stItem);
    CHECK_EXPR(iRet == 0, -1, "item maybe deleted: {} num:{}", stItem.base().id(), stItem.base().value());

    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::AddCapacity(int iNum, int* pOrgCapacity, int* pNewCapacity)
{
    NF_ASSERT(m_iCapacity == m_astItemList.size());
    CHECK_EXPR(iNum > 0, -1, "NFBagPageImpl", "Invalid Capacity Increment:%d Info:%s", iNum, GetDebugInfo());
    CHECK_EXPR(m_iCapacity + iNum <= MAX_ITEM_NUM, proto_ff::ERR_CODE_BAG_GRID_OPEN_MAX, "error : can not add: {} {} {}", iNum, m_astItemList.size(), m_astItemList.max_size());
    ++m_iOpenGridTimes;

    if (pOrgCapacity)
    {
        *pOrgCapacity = m_iCapacity;
    }

    m_iCapacity = m_iCapacity + iNum;
    m_astItemList.resize(m_iCapacity);

    if (pNewCapacity)
    {
        *pNewCapacity = m_iCapacity;
    }
    LOGSVR_INFO("grid add to: " << m_iCapacity);
    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::DecCapacity(int iNum, int* pOrgCapacity, int* pNewCapacity)
{
    NF_ASSERT(m_iCapacity == m_astItemList.size());
    CHECK_EXPR(iNum > 0, -1, "NFBagPageImpl", "Invalid Capacity Increment:%d Info:%s", iNum, GetDebugInfo());
    CHECK_EXPR((int)m_iCapacity - iNum <= 0, proto_ff::ERR_CODE_BAG_GRID_OPEN_MAX, "error : can not dec: {} capacity:{} max size:{}", iNum, m_astItemList.size(), m_astItemList.max_size());
    CHECK_EXPR((int)m_iCapacity - iNum <= m_iUsedNum, proto_ff::ERR_CODE_BAG_GRID_OPEN_MAX, "error : can not dec:{} usedNum:{} capacity:{} maxsize:{} ", iNum, m_iUsedNum, m_astItemList.size(), m_astItemList.max_size());
    ++m_iOpenGridTimes;

    if (pOrgCapacity)
    {
        *pOrgCapacity = m_iCapacity;
    }

    m_iCapacity = m_iCapacity - iNum;
    m_astItemList.resize(m_iCapacity);

    if (pNewCapacity)
    {
        *pNewCapacity = m_iCapacity;
    }
    LOGSVR_INFO("grid add to: " << m_iCapacity);
    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::SetCapacity(int iNewCapacity)
{
    NF_ASSERT(m_iCapacity == m_astItemList.size());
    CHECK_EXPR((iNewCapacity >= 0), -1, "Invalid Capacity NewCapacity:{} Info:{}", iNewCapacity, GetDebugInfo());
    CHECK_EXPR(iNewCapacity >= m_iUsedNum, -1, "Invalid Capacity NewCapacity:{} Info:{}", iNewCapacity, m_iUsedNum, GetDebugInfo());
    CHECK_EXPR(iNewCapacity <= MAX_ITEM_NUM, -1, "Invalid Capacity NewCapacity:{} Info:{}", iNewCapacity, m_iUsedNum, GetDebugInfo());
    m_iCapacity = iNewCapacity;
    m_astItemList.resize(m_iCapacity);
    return 0;
}

template <size_t MAX_ITEM_NUM>
uint64_t NFBagPageImpl<MAX_ITEM_NUM>::GetItemNum(int iID) const
{
    if (iID <= 0) return 0;

    uint64_t num = 0;
    for (int i = 0; i < static_cast<int>(m_astItemList.size()); i++)
    {
        const NFGridItem& item = m_astItemList[i];
        if (item.m_stBase.id == iID)
        {
            num += item.m_stBase.value;
        }
    }
    return num;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::GetAllItemOut(std::vector<NFGridItem>& vecGridItem) const
{
    for (int i = 0; i < static_cast<int>(m_astItemList.size()); i++)
    {
        const NFGridItem& item = m_astItemList[i];
        if (!item.IsEmpty())
        {
            vecGridItem.push_back(item);
        }
    }
    return 0;
}

template <size_t MAX_ITEM_NUM>
NFGridItem* NFBagPageImpl<MAX_ITEM_NUM>::GetItemByIndex(int iIndex)
{
    int iRetCode = CheckValidGridIndex((uint32_t)iIndex);
    CHECK_WARN_RE_NULL(m_roleID, iRetCode, "CheckValidGridIndex({}) fail", iIndex);
    return &m_astItemList[iIndex];
}

template <size_t MAX_ITEM_NUM>
const NFGridItem* NFBagPageImpl<MAX_ITEM_NUM>::GetItemByIndex(int iIndex) const
{
    int iRetCode = CheckValidGridIndex((uint32_t)iIndex);
    CHECK_WARN_RE_NULL(m_roleID, iRetCode, "CheckValidGridIndex({}) fail", iIndex);
    return &m_astItemList[iIndex];
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::GetItemByIndex(NFGridItem* pOutItem, int iIndex) const
{
    CHECK_NULL(m_roleID, pOutItem);
    const NFGridItem* pItem = GetItemByIndex(iIndex);
    if (pItem && !pItem->IsEmpty())
    {
        *pOutItem = *pItem;
        return 0;
    }

    return -1;
}

template <size_t MAX_ITEM_NUM>
NFGridItem* NFBagPageImpl<MAX_ITEM_NUM>::GetItemByUUID(uint64_t uuid)
{
    if (m_iUsedNum == 0)
    {
        return NULL;
    }

    for (int i = 0; i < static_cast<int>(m_astItemList.size()); i++)
    {
        NFGridItem& item = m_astItemList[i];
        if (item.GetUUID() == uuid)
        {
            return &item;
        }
    }
    return nullptr;
}

template <size_t MAX_ITEM_NUM>
const NFGridItem* NFBagPageImpl<MAX_ITEM_NUM>::GetItemByUUID(uint64_t uuid) const
{
    if (m_iUsedNum == 0)
    {
        return NULL;
    }

    for (int i = 0; i < static_cast<int>(m_astItemList.size()); i++)
    {
        const NFGridItem& item = m_astItemList[i];
        if (item.GetUUID() == uuid)
        {
            return &item;
        }
    }
    return nullptr;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::GetItemByUUID(NFGridItem* pOutItem, uint64_t uuid) const
{
    CHECK_NULL(m_roleID, pOutItem);
    const NFGridItem* pItem = GetItemByUUID(uuid);
    if (pItem)
    {
        *pOutItem = *pItem;
        return 0;
    }

    return -1;
}

template <size_t MAX_ITEM_NUM>
NFGridItem* NFBagPageImpl<MAX_ITEM_NUM>::GetEmptyGrid(int& iIndex)
{
    for (int i = 0; i < static_cast<int>(m_astItemList.size()); i++)
    {
        NFGridItem& item = m_astItemList[i];
        if (NFItemUtil::IsEmptyGrid(item))
        {
            iIndex = i;
            return &item;
        }
    }
    iIndex = INVALID_ID;
    return nullptr;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::DoOneOperation(int iTargetGridIndex, NFItemOperator* pItemOperator, NFGridItem* pItemOrgOut, NFGridItem* pItemNewOut)
{
    int iRetCode = 0;
    CHECK_EXPR(m_iUsedNum > 0, -1, "Package Empty Info:{}", GetDebugInfo());
    CHECK_NULL(m_roleID, pItemOperator);

    iRetCode = CheckValidGridIndex((uint32_t)iTargetGridIndex);
    CHECK_RET(iRetCode, "CheckValidGridIndex Failed GridIndex:{} Info:{}", iTargetGridIndex, GetDebugInfo());

    NFGridItem& stItem = m_astItemList[iTargetGridIndex];
    if (pItemOrgOut)
    {
        *pItemOrgOut = stItem;
    }

    if (pItemOperator)
    {
        pItemOperator->DoOperation(&stItem);
    }

    if (pItemNewOut)
    {
        *pItemNewOut = stItem;
    }
    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::Sort()
{
    if (m_astItemList.size() <= 1)
    {
        return 0;
    }

    int iSize = m_astItemList.size();
    if (m_iPageType == EN_BPT_TEMP_STORAGE)
    {
        auto first = m_astItemList.begin();
        auto last = m_astItemList.end();
        bool canDelete = false;
        for (auto iter = m_astItemList.begin(); iter != m_astItemList.end();)
        {
            if (canDelete == false)
            {
                if (iter->IsEmpty())
                {
                    canDelete = true;
                    first = iter;
                }
            }
            else
            {
                if (!iter->IsEmpty())
                {
                    last = iter;
                    iter = m_astItemList.erase(first, last);
                    canDelete = false;
                    continue;
                }
            }
            ++iter;
        }
        m_astItemList.resize(iSize);
        m_iUsedNum = 0;
        for (auto iter = m_astItemList.begin(); iter != m_astItemList.end(); ++iter)
        {
            if (!iter->IsEmpty())
            {
                m_iUsedNum++;
            }
        }
    }
    else
    {
        m_iUsedNum = 0;
        NFItemSorter stSorter(m_astItemList.size());
        for (int i = 0; i < (int)m_astItemList.size(); i++)
        {
            stSorter.Append(m_astItemList[i]);
        }
        stSorter.Sort();
        m_astItemList.Init();
        m_astItemList.resize(iSize);

        for (int i = 0; i < (int)stSorter.Count(); i++)
        {
            NFGridItem stItem;
            stSorter.Get(i, stItem);
            int iPileNumMax = 0;
            int iRetCode = NFItemUtil::GetItemPileNumMax(stItem.m_stBase.id, iPileNumMax);
            if (iRetCode != 0)
            {
                LOGSVR_FATAL(" can not find ItemDesc: " << stItem.m_stBase.id << " index: " << i << " Total: " << stSorter.Count());
                continue;
            }

            while (stItem.m_stBase.value > 0)
            {
                NFGridItem& newItem = m_astItemList[m_iUsedNum];
                newItem = stItem;
                if (iPileNumMax > 0 && stItem.m_stBase.value > (uint64_t)iPileNumMax)
                {
                    newItem.m_stBase.value = iPileNumMax;
                    stItem.m_stBase.value -= iPileNumMax;
                }
                else
                {
                    stItem.m_stBase.value = 0;
                }
                ++m_iUsedNum;
            }
        }
    }

    return 0;
}

template <size_t MAX_ITEM_NUM>
void NFBagPageImpl<MAX_ITEM_NUM>::Reset()
{
    m_iUsedNum = 0;
    m_astItemList.Init();
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::CheckValidGridIndex(uint32_t dwGridIndex) const
{
    if (dwGridIndex >= m_astItemList.size() || dwGridIndex >= m_astItemList.max_size())
    {
        return -1;
    }
    return 0;
}

template <size_t MAX_ITEM_NUM>
bool NFBagPageImpl<MAX_ITEM_NUM>::IsFull() const
{
    if (m_iUsedNum >= m_astItemList.size() || m_iUsedNum >= m_astItemList.max_size())
    {
        return true;
    }
    return false;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::FindEmptyGridIndex() const
{
    for (int i = 0; i < static_cast<int>(m_astItemList.size()); i++)
    {
        const NFGridItem& item = m_astItemList[i];
        if (NFItemUtil::IsEmptyGrid(item))
        {
            return i;
        }
    }
    return INVALID_ID;
}

template <size_t MAX_ITEM_NUM>
const std::string NFBagPageImpl<MAX_ITEM_NUM>::GetDebugInfo() const
{
    std::stringstream str;
    str << "Capacity:" << m_astItemList.size() << " TotalNum:" << m_iUsedNum << " Max:" << m_astItemList.max_size() << " PageType:" << m_iPageType;
    return str.str();
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::CheckIsGridEmpty(int iTargetGridIndex, bool* pbIsEmpty) const
{
    int iRet = CheckValidGridIndex(iTargetGridIndex);
    CHECK_RET(iRet, "CheckValidGridIndex Failed, iTargetGridIndex:{} info:{}", iTargetGridIndex, GetDebugInfo());

    const NFGridItem& stItem = m_astItemList[iTargetGridIndex];

    if (pbIsEmpty)
    {
        *pbIsEmpty = stItem.IsEmpty();
    }

    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::GetItem(NFGridItem* pItemOut, int iTargetGridIndex) const
{
    int iRet = CheckValidGridIndex(iTargetGridIndex);
    CHECK_RET(iRet, "CheckValidGridIndex Failed, iTargetGridIndex:{} info:{}", iTargetGridIndex, GetDebugInfo());
    CHECK_EXPR(m_iUsedNum > 0, -1, "Package Empty Info:{}", GetDebugInfo());

    const NFGridItem& stItem = m_astItemList[iTargetGridIndex];
    CHECK_EXPR(!stItem.IsEmpty(), -1, "TargetGrid is empty, GridIndex:{} Info:{}", iTargetGridIndex, GetDebugInfo());

    *pItemOut = stItem;
    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::SetItem(int iGridIndex, const NFGridItem* pItem, bool bPreCheckFlag)
{
    CHECK_NULL(m_roleID, pItem);
    NFGridItem* pOldItem = GetItemByIndex(iGridIndex);
    CHECK_NULL_WF(m_roleID, pOldItem, "iGridIndex:{}", iGridIndex);

    if (bPreCheckFlag)
    {
        return 0;
    }

    if (pOldItem->GetNumber() <= 0)
    {
        if (pItem->GetNumber() > 0)
        {
            ++m_iUsedNum;
        }
        else
        {
            return 0;
        }
    }
    else
    {
        if (pItem->GetNumber() <= 0)
        {
            --m_iUsedNum;
        }
    }

    if (pItem->GetNumber() <= 0)
    {
        pOldItem->Init();
    }
    else
    {
        *pOldItem = *pItem;
    }
    return 0;
}


template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::AddItem(const NFGridItem* pItem, int* pGridIndexOut)
{
    CHECK_NULL(m_roleID, pItem);
    CHECK_EXPR(!IsFull(), -1, "Package Full, Info:{}", GetDebugInfo());

    int iGridIndex = FindEmptyGridIndex();
    CHECK_EXPR(iGridIndex != INVALID_ID, -1, "FindEmptyGridIndex failed, Info:{}", GetDebugInfo());

    if (pGridIndexOut)
    {
        *pGridIndexOut = iGridIndex;
    }

    NFGridItem& stItem = m_astItemList[iGridIndex];
    stItem = *pItem;
    m_iUsedNum++;
    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::AddItemWithGrid(const NFGridItem* pItem, int iTargetGridIndex)
{
    CHECK_NULL(m_roleID, pItem);
    int iRet = CheckValidGridIndex(iTargetGridIndex);
    CHECK_RET(iRet, "CheckValidGridIndex Failed, iTargetGridIndex:{} info:{}", iTargetGridIndex, GetDebugInfo());
    CHECK_EXPR(!IsFull(), -1, "Package Full, Info:{}", GetDebugInfo());

    NFGridItem& stItem = m_astItemList[iTargetGridIndex];
    CHECK_EXPR(stItem.IsEmpty(), -1, "TargetGrid is not empty, GridIndex:{} Info:{}", iTargetGridIndex, GetDebugInfo());

    stItem = *pItem;
    m_iUsedNum++;
    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::DecItem(int iTargetGridIndex, NFGridItem* pDelItemOut)
{
    int iRet = CheckValidGridIndex(iTargetGridIndex);
    CHECK_RET(iRet, "CheckValidGridIndex Failed, iTargetGridIndex:{} info:{}", iTargetGridIndex, GetDebugInfo());
    CHECK_EXPR(m_iUsedNum > 0, -1, "Package Empty Info:{}", GetDebugInfo());

    NFGridItem& stItem = m_astItemList[iTargetGridIndex];
    CHECK_EXPR(!stItem.IsEmpty(), -1, "TargetGrid is empty, GridIndex:{} Info:{}", iTargetGridIndex, GetDebugInfo());

    if (pDelItemOut != NULL)
    {
        *pDelItemOut = stItem;
    }

    stItem.Reset();
    m_iUsedNum--;
    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::AddItemNum(int iTargetGridIndex, int iTargetIncreaseNum, NFGridItem* pItemOrgOut, NFGridItem* pItemNewOut)
{
    int iRetCode = 0;
    iRetCode = CheckValidGridIndex((uint32_t)iTargetGridIndex);
    CHECK_ERR(m_roleID, iRetCode, "CheckValidGridIndex Failed GridIndex:{} Info:{}", iTargetGridIndex, GetDebugInfo());

    NFGridItem& stOrgItem = m_astItemList[iTargetGridIndex];
    if (stOrgItem.IsEmpty() == true)
    {
        CHECK_ERR(m_roleID, -1, "TargetGrid Is Empty Error GridIndex:{} Info:{}", iTargetGridIndex, GetDebugInfo());
    }

    if (pItemOrgOut)
    {
        *pItemOrgOut = stOrgItem;
    }

    stOrgItem.AddNumber(iTargetIncreaseNum);

    if (pItemNewOut)
    {
        *pItemNewOut = stOrgItem;
    }

    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::DecItemNum(int iTargetGridIndex, int iTargetDecreaseNum, NFGridItem* pItemOrgOut, NFGridItem* pItemNewOut)
{
    int iRetCode = 0;
    iRetCode = CheckValidGridIndex((uint32_t)iTargetGridIndex);
    CHECK_ERR(m_roleID, iRetCode, "CheckValidGridIndex Failed GridIndex:{} Info:{}", iTargetGridIndex, GetDebugInfo());

    NFGridItem& stOrgItem = m_astItemList[iTargetGridIndex];
    if (stOrgItem.IsEmpty() == true)
    {
        CHECK_ERR(m_roleID, -1, "TargetGrid Is Empty Error GridIndex:{} Info:{}", iTargetGridIndex, GetDebugInfo());
    }

    if (stOrgItem.GetNumber() <= iTargetDecreaseNum)
    {
        CHECK_ERR(m_roleID, -1, "stOrgItem.GetNumber() <= iTargetDecreaseNum Error, TargetGrid:{} DecreaseNum:{} Info:{}", iTargetGridIndex, iTargetDecreaseNum, GetDebugInfo());
        return -1;
    }

    if (pItemOrgOut)
    {
        *pItemOrgOut = stOrgItem;
    }

    stOrgItem.DecNumber(iTargetDecreaseNum);

    if (pItemNewOut)
    {
        *pItemNewOut = stOrgItem;
    }
    return 0;
}

template <size_t MAX_ITEM_NUM>
int NFBagPageImpl<MAX_ITEM_NUM>::CheckDataMatched(int iTargetGridIndex, int iItemID, uint64_t ullUID, int iNum) const
{
    int iRetCode = 0;

    iRetCode = CheckValidGridIndex((uint32_t)iTargetGridIndex);
    CHECK_ERR(m_roleID, iRetCode, "CheckValidGridIndex Failed GridIndex:{} Info:{}", iTargetGridIndex, GetDebugInfo());

    if (m_iUsedNum == 0)
    {
        CHECK_ERR(m_roleID, -1, "Container Is Empty Error GridIndex:{} Info:{}", iTargetGridIndex, GetDebugInfo());
    }

    const NFGridItem& stOrgItem = m_astItemList[iTargetGridIndex];
    if (stOrgItem.IsEmpty() == true)
    {
        CHECK_ERR(m_roleID, -1, "TargetGrid Is Empty Error GridIndex:{} Info:{}", iTargetGridIndex, GetDebugInfo());
    }

    //when iResID == 0, means no need check resid info
    if (iItemID != 0 && stOrgItem.GetItemID() != iItemID)
    {
        CHECK_ERR(m_roleID, -1, "ResID Not Matched ReqResID:{} OrgResID:{} GridIndex:{} Info:{}", iItemID,stOrgItem.GetItemID(), iTargetGridIndex, GetDebugInfo());
    }

    //when iResID == 0, means no need check resid info
    if (ullUID != 0 && stOrgItem.GetUUID() != ullUID)
    {
        CHECK_ERR(m_roleID, -1, "UUID Not Matched ReqUID:{} OrgUID:{} GridIndex:{} Info:{}", ullUID,stOrgItem.GetItemID(), iTargetGridIndex, GetDebugInfo());
    }

    //when iResID == 0, means no need check resid info
    if (iNum != 0 && stOrgItem.GetNumber() != iNum)
    {
        CHECK_ERR(m_roleID, -1, "WareNum Not Matched ReqNumber:{} OrgNumber:{} GridIndex:{} Info:{}", iNum, stOrgItem.GetItemID(), iTargetGridIndex, GetDebugInfo());
    }
    return 0;
}
